import { RepoLink, Link } from '@brillout/docpress'
import PreRenderDynamicRoutes from './PreRenderDynamicRoutes.mdx'


## What is pre-rendering?

Pre-rendering means to render the HTML of pages at build-time (when running <Link href="/cli">`$ vike build`</Link>).

Without pre-rendering, the HTML of a page is rendered at request-time (when the user goes to that page).

If you pre-render all your pages, you don't need a production server: your app consists only of a static assets (HTML, JS, CSS, images, ...) that can be deployed to a static host (<Link href="/github-pages" text="GitHub Pages" />, <Link href="/cloudflare-pages">Cloudflare Pages</Link>, <Link href="/netlify">Netlify</Link>, ...).

If you don't pre-render, you need a production server to dynamically render your pages' HTML at request-time. (Deploying a [Node.js](https://nodejs.org) server to [AWS](https://aws.amazon.com), <Link href="/cloudflare" text="Cloudflare Workers" />, <Link href="/vercel" text="Vercel" />...)

> Tools that pre-render pages are also known as "SSG" (Static-Site Generators).


## Should I pre-render?

In a nutshell: **pre-render your pages whenever you can**.

Because pre-rendering removes the need for a production server and makes deployment very easy and very cheap (usually free). It's also significantly more performant as the HTML isn't re-generated on every HTTP request.

But **pre-rendering cannot be used for websites with content that changes very frequently**. For example [Hacker News](https://news.ycombinator.com) or [Reddit](https://www.reddit.com): users are constantly creating new posts, which would require pre-rendering to run again each time — pre-rendering the entire website (millions of pages) every millisecond isn't possible.

> In theory, it's possible to re-render only the subset of pages that are affected by new content, but it isn't practical (it has been tried before) and we recommend against this practice.

> Technically, the bottom line is: how frequently does the HTML of your pages change? See:
> - <Link href="#ssg-vs-ssr" />
> - <Link href="/SSR-vs-SPA" />

**Pre-rendering can be used for websites with content that changes only occasionally**. For example, the content of `https://vike.dev` changes only when a maintainer updates the documentation — the entire website `https://vike.dev` can then be pre-rendered again every time there is change.

> This website `https://vike.dev` uses pre-rendering and is deployed to <Link href="/github-pages" text="GitHub Pages" /> — a static host that is completely free, [easy to use](https://github.com/vikejs/vike/blob/main/.github/workflows/website.yml), and performant.


## Get started

To enable pre-rendering:

```ts
// pages/+config.ts

import type { Config } from 'vike/types'

export default {
  prerender: true
} satisfies Config
```

Your pages' HTML are now rendered at build-time (when you run <Link href="/cli">`$ vike build`</Link>) instead of request-time.

The generated `.html` files are written to `dist/client/`.

### CLI instead of server

With pre-rendering, you don't need a JavaScript server — you can use <Link href="/cli">`$ vike dev` and `$ vike preview`</Link> instead. (You do, however, need a JavaScript server if <Link href="#partial">you skip pre-rendering some pages</Link>.)

### Parameterized routes

For a page with a parameterized route (e.g. `/movie/@id`), you must use the <Link href="/onBeforePrerenderStart">`onBeforePrerenderStart()` hook</Link> to provide the list of URLs to be pre-rendered.

<PreRenderDynamicRoutes />


## Configuration

Common `+prerender` options:

```ts
// pages/+config.ts

import type { Config } from 'vike/types'

export default {
  prerender: {
    noExtraDir: true, // Don't create a new directory for each HTML file
    parallel: false // Disable concurrency — pre-render pages sequentially (one by one)
    // ...
  }
} satisfies Config
```

> See <Link href="/prerender" /> for the list of all options.

You can also:
 - Pre-render only some pages (instead of pre-rendering all pages), see <Link href="#partial" />.
 - Define redirections, see <Link href="/prerender#redirects" />.
 - Use  <Link href="/api#prerender">Vike's `prerender()` API</Link> to invoke the pre-rendering process programmatically (instead of being run automatically on `$ vike build`).
 - Accelerate the pre-rendering process by using the <Link href="/onBeforePrerenderStart">`onBeforePrerenderStart()` hook</Link>.

## Partial

By default, all pages are pre-rendered, but you can also pre-render only some pages.

### Opt-out

You can set `prerender: false` to skip a page from pre-rendering:

```ts
// /pages/+config.ts

import type { Config } from 'vike/types'

export default {
  // Pre-render all pages by default
  prerender: true
} satisfies Config
```

```ts
// /pages/news/+config.ts

import type { Config } from 'vike/types'

export default {
  // Skip pre-rendering for /pages/news/+Page.ts
  prerender: false
} satisfies Config
```

> For example, a news page that displays the latest news fetched from a database should be rendered at request-time (not at build-time).
>
> See also: <Link href="/pre-rendering#should-i-pre-render" doNotInferSectionTitle />

You can also disable pre-rendering for a group of pages:

```ts
// /pages/products/+prerender.ts

// Applies to all /pages/products/**/+Page.ts
export const prerender = false
```

> See also: <Link href="/config#inheritance" />

### Opt-in instead of opt-out

You can make pre-rendering opt-in instead of opt-out:

```ts
// /pages/+config.ts

import type { Config } from 'vike/types'

export default {
  // By default, pages aren't pre-rendered
  prerender: false
} satisfies Config
```

```ts
// /pages/(marketing)/+prerender.ts

// Applies to all marketing pages /pages/(marketing)/**/+Page.ts
export const prerender = true
```

> The directory `(marketing)` is ignored by Filesystem Routing, see <Link href="/routing#groups" />.

### Dynamic condition

You can dynamically disable/enable pre-rendering:

```ts
// /pages/+prerender.ts

export const prerender = someCondition() ? false : true
```

> For example, to disable pre-rendering when previewing CMS changes:
> ```ts
> // /pages/+prerender.ts
>
> export const prerender = process.env.MODE !== 'preview'
> ```

Note that <Link href="/onBeforePrerenderStart">`onBeforePrerenderStart()` hooks</Link> are always called, even if `prerender` is `false`.
If you want to define `onBeforePrerenderStart()` conditionally:

```ts
// /pages/movie/+prerender.ts

export { prerender }

import { someCondition } from './someCondition'

const prerender = someCondition()
```

```ts
// /pages/movie/+onBeforePrerenderStart.ts

export { onBeforePrerenderStart }

import { someCondition } from './someCondition'

const onBeforePrerenderStart = someCondition()
  ? async () => {
      // ...
    }
  : null
```


## SSG vs SSR

The only difference between SSG and SSR is *when* the HTML is rendered:
- **SSG**: the HTML of the page is rendered at build-time (when calling <Link href="/cli">`$ vike build`</Link>).
- **SSR**: the HTML of the page is rendered at request-time (when the user goes to the page).

> The **client-side code** of the page is always loaded and executed in the user's browser at request-time (regardless of SSG and SSR).

> If you pre-render all your pages, there's no server — all "server-side code" runs at build-time. Calling it "server-side code" is technically a misnomer, but we keep the term for simplicity. One way to think about pre-rendering is that it essentially means "pre-rendered SSR (Server-Side Rendering)".

Essentially, and technically, SSG means SSR + pre-rendering:

```ts
// pages/+config.ts

import type { Config } from 'vike/types'

// SSG
export default {
  prerender: true,
  ssr: true // (optional: `ssr` is true by default)
} satisfies Config
```

See also:
- <Link href="/prerender" />
- <Link href="/ssr" />
- <Link href="/SSR-vs-SPA" />


## Can I use SSG + SPA?

Yes, you can have SPA pages while others are SSG.

You usually still pre-render all your pages, including SPA pages. (See explanation below.)

For example:

```yaml
pages/+config.ts
pages/(marketing)/+config.ts
pages/(marketing)/index/+Page.ts # SSR
pages/(marketing)/about/+Page.ts # SSR
pages/admin-panel/+config.ts
pages/admin-panel/index/+Page.ts # SPA
```

```ts
// pages/+config.ts

import type { Config } from 'vike/types'

export default {
  // Pre-render *all* pages (including SPA pages)
  prerender: true
} satisfies Config
```

```ts
// pages/admin-panel/about/+Page.ts

import type { Config } from 'vike/types'

export default {
  // SPA
  ssr: false
} satisfies Config
```

```ts
// pages/(marketing)/about/+Page.ts

import type { Config } from 'vike/types'

export default {
  // SSG
  ssr: true // (optional: `ssr` is true by default)
} satisfies Config
```

> SPA means the page is rendered only on the client-side (see <Link href="/what-is-SSR-and-SPA" />). In other words, <Link href="/ssr">no SSR</Link>:
>
> ```ts
> // pages/+config.ts
>
> import type { Config } from 'vike/types'
>
> // SPA
> export default {
>   ssr: false
> } satisfies Config
> ```
>
> But when the user visits an SPA page, the browser still needs an HTML response to kick off client-side rendering. This HTML is just an empty shell (it doesn't contain the content of the page). If you want to avoid the need for a production server, you can pre-render this empty shell:
>
> ```ts
> // pages/+config.ts
>
> import type { Config } from 'vike/types'
>
> // SPA
> export default {
>   prerender: true,
>   ssr: false
> } satisfies Config
> ```
>
> That's why the common practice is to set `ssr: false` together with `prerender: true`.
>
> In a nutshell: the only difference is that the content of your SSG pages is included in the HTML, while the content of your SPA pages isn't.
>
> Even though the content of SPA pages is missing, meta information (title, description, social image, ...) is still included in the pre-rendered HTML. See <Link href="/head-tags#spa" />.


## Can I use SSG + SSR?

Yes, you can have SSR pages while others are SSG.

> SSG is basically "pre-rendered SSR", see <Link href="#ssg-vs-ssr" />.

For example:

```yaml
pages/+config.ts
pages/user/@id/+Page.ts # SSR
pages/(marketing)/+config.ts
pages/(marketing)/index/+Page.ts # SSG
pages/(marketing)/about/+Page.ts # SSG
```

```ts
// pages/+config.ts

import type { Config } from 'vike/types'

// SSR
export default {
  ssr: true // (optional: `ssr` is true by default)
} satisfies Config
```

```ts
// pages/(marketing)/+config.ts

import type { Config } from 'vike/types'

// SSG
export default {
  prerender: true,
  ssr: true // (optional: `ssr` is inherited by pages/+config.ts)
} satisfies Config
```

> See also:
> - <Link href="/ssr" />
> - <Link href="#ssg-vs-ssr" />
> - <Link href="/config#inheritance" />


## See also

- <Link href="/data-fetching#pre-rendering-ssg" doNotInferSectionTitle />
- <Link href="/static-hosts" />
- <Link href="/SSR-vs-SPA" />
- <Link href="/ssr" />

Pre-rendering options:

- <Link href="/prerender" />
- <Link href="/onBeforePrerenderStart" />
- <Link href="/onPrerenderStart" />
- <Link href="/api#prerender" doNotInferSectionTitle />
- <Link href="/cli" />
- <Link href="/ssr" />
